/*最近公共祖先(LCA)

* 1.向上标记法O(n)
    (1) 从x向上走到根节点，并标记所有经过的结点
    (2)从y向上走到根节点，当第一次遇到已经标记的结点时，就找到了LCA(x,y);

* 2.树上倍增法O((n+m)logn):预处理O(nlogn),每次查询(logn)
    核心数组fa[i][j]:表示从i结点开始，向上走2^j远的祖先结点, 0<=j<=logn
    (1)bfs得到每个结点所处的深度depth[]。根节点为1，越界结点fa[0]=0, depth[x]表示x的深度。
    (2)用二进制拆分，找到a的，b同深度的祖先。（假设a深度大于b）。
    (3)如果此时a==b，那么b是a祖先结点，此时a就是LCA(a,b);
    (4)如果此时a!=b,我们仍然二进制拆分，使得fa[a][i] == fa[b][i];
    (5)此时 a、b,是最近公共祖先的子节点。fa[a][0] == fa[b][0] == LCA(a,b);

* 3.(tarjan求最近公共祖先) O(n+m)
    tarjan是一种离线查询算法
    所谓离线就是将所有查询先记录下来，然后计算好所有的中间过程，最后再将所有的查询记录对应的结果依次输出

    tarjan是基于向上标记法的一种优化
    首先树上两个结点之间的距离是等于 结点u到根节点的距离 + 结点v到根节点的距离 - 2 * 结点u、v的最近公共祖先到根节点的距离 
                                  <-> dist[u,v] = dist[u] + dist[v] - 2 * dist[LCA(u,v)]

    tarjan算法如何求解最近公共祖先:
    首先它将整棵树上的结点分为三部分
    (1)已经搜索完且回溯过的点 标记为 2
    (2)正在搜索的分支结点 标记为 1
    (3)还未搜索到的结点 标记为 0

    * 核心：
        对于已经被标记为 2 的点 和当前正在搜索的分支存在一种关系，就是
        (1)所有被标记为 2 的点都可以合并压缩到当前正在搜索的分支中的某个结点上，这一步操作可以用并查集实现
        (2)因此当我们搜索完且回溯当前结点的时候，可以遍历关于当前结点u的所有有关询问，
           其中询问中对标记为 2 的结点与当前结点u的最近公共祖先就是标记为 2 的结点在并查集中的代表元素（根节点/祖宗）

* 4.严格次小生成树
    枚举每一组非树边，重复3步骤，最后维护一个全局最小值即是次小生成树
    * 步骤: 
    (1)首先用kruskal求出最小生成树的节点和边,并且将这些点和边建成邻接表
    (2)用倍增法预处理出fa,d1和d2数组的值，其中计算d1和d2的值和计算fa数组的值差不多都是使用递推的方式
    (3)预处理完之后就开始用非树边的权值替换掉树边的最大或次大权值，在将节点a和b节点倍增到同一层的过程中，
        顺便记录下途中经过路径的d1和d2的值，跳到同一层之后开始同步跳直到跳到祖宗节点为止，过程中也记录下d1和d2的值，最后选出最小的d1和d2的值，并且用非树边替换掉它。
    (4)枚举每一组非树边，重复3步骤，最后维护一个全局最小值即是次小生成树

    * 核心思路:
    就是使用倍增法计算出从a到祖宗节点和b到祖宗节点这两段路径中树边的最大权值dist1和次大权值dist2，
    最后枚举每一组非树边，例如对于其中一组a−>b,替换掉dist1或者dist2（加入一条非树边减去一条树边），最后维护全局的最小值即是次小生成树
    
* 注意点：
    (1)lca中的第一个for，目的是找到a的，和b同深度的祖先结点。一定要从大到小遍历。
    (2)lca中的第二个for，目的是让a和b分别转移到LCA(a,b)的子节点上，一定要从大到小遍历。
    (3)本题中lca第二个for从小到大遍历也能过，是因为没要求输出正确LCA(a,b),只要求判断。
    (4)第一for目的是让距离t变为0，第二个for目的是让t变为1。
    (5)我们只有从最高位1遍历，才能根据唯一的二进制形式达到要求。

*/

#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
// #define ONLINE_GUDGE
using namespace std;

const int N = 100010, M = 600010, INF = 0x3f3f3f3f;

int n, m;
int h[N], e[M], ne[M], idx;
int d[N];
int depth[N], fa[N][17];
int ans; // 存储最小生成树的总权重

void add(int a, int b)// , int c)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++; // w[idx] = c, 
}

void bfs()
{
    memset(depth,0x3f,sizeof depth);
    queue<int> q;
    depth[0] = 0,depth[1] = 1;
    q.push(1);

    while(q.size())
    {
        auto u = q.front();q.pop();
        for(int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];

            // 每个节点只有一个父节点，只会初始化(访问)一次，在无向图中，只需特判不直接相连即可
            if(depth[v] > depth[u] + 1){ 
                depth[v] = depth[u] + 1;               
                q.push(v);
                fa[v][0] = u; // 往上走2^0=1，就是父节点
                for(int k = 1; k <= 16; k++)
                    fa[v][k] = fa[fa[v][k-1]][k-1]; // v向上走2^k的节点是v向上走2^(k-1) * 2^(k-1)的节点
                
            }
        }
    }
}

int lca(int a, int b)
{
    // 默认a的深度深于b，方便之后操作
    if (depth[a] < depth[b]) swap(a, b);

    // 这一步是要找到 1.a的 2.和b在同一深度的 祖先。
    // 我们假设 t = depth[a] - depth[b]; 将t看成一个二进制数，可以不断地寻找t的最高位的1
    // t每次减去一个最高位的1的距离(2^i)，最终t就会为0，就找到了 1.a的 2.和b在同一深度的 祖先。
    // 注意，我们找的是最高位的1，所以从大到小遍历
    for (int k = 16; k >= 0; k--)
    {
        // 对深度进行判断，越界的深度都是0
        if (depth[fa[a][k]] >= depth[b])
            a = fa[a][k];
    }
    
    // 这里我们只是单纯的找到a的，和b在同一深度的祖先
    // 如果此时二者就相等了，那么说明b就是a的(最近公共)祖先
    if (a == b)
        return a;


    // 此时a，b同层，但是不同结点，二者距离最近公共祖先的长度是一样的, a,b此时一起向上走也是一样的
    // 如果 fa[a][i] != fa[b][i]，那么二者距离最近公共祖先的距离起码还有 2^i
    // 所以 a = fa[a][i], b = fa[b][i]
    for (int i = 16; i >= 0; i--)
    {
        if (fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    // 此时f[a][0] == f[b][0]，a、b是最近公共祖先的子节点。
    return fa[a][0];
}

// dfs 返回每一棵子树的和
int dfs(int u, int father)
{
    // 遍历以u为根节点的子树j的和 
    int res = d[u];
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if (v != father)
        {
            // 边t→j 砍掉后的方案 s
            int s = dfs(v, u);
            // 如果s=0 则随便砍
            if (s == 0) ans += m;
            // 如果s=1 则只能砍对应的非树边
            else if (s == 1) ans ++ ;
            // 子节点j的差分向上加给/传给 节点u
            res += s;
        }
    }
    // 如果没有子节点 即叶子节点 直接返回d[node]
    return res;
}

int main()
{

    #ifdef ONLINE_JUDGE

    #else
    freopen("./in.txt","r",stdin);
    #endif
    // ios::sync_with_stdio(false);   
	// cin.tie(0);

    cin >> n >> m;
    memset(h, -1, sizeof h);
    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b; cin >> a >> b;
        add(a, b), add(b, a);
    }

    bfs();

    // 读入附加边==非树边
    for (int i = 0; i < m; i ++ )
    {
        int a, b; cin >> a >> b;
        int p = lca(a, b);
        d[a] ++, d[b] ++, d[p] -= 2;
    }

    dfs(1, -1);

    cout << ans << endl;

    return 0;
}